﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MvCamCtrl.NET;
using System.Runtime.InteropServices;
using VisionApp.Entity;
using VisionApp.Interface;

namespace VisionApp.Camera
{
    public class HIKCamera2 : ICamera
    {
        public HImageContainer ImCtnr { get; set; }
        public bool Connected { get; set; }
        public List<string> DeviceIDList { get; set; }
        public CameraInfo CurrentCameraInfo { get; set; }
        private Logger _log;
        private int nRet = MyCamera.MV_OK;
        private Dictionary<string, MyCamera> _deviceDict = new Dictionary<string, MyCamera>();
        UInt32 nPayloadSize;
        public HIKCamera2(ILogger log)
        {
            _log = (Logger)log;
            ImCtnr = new HImageContainer();
        }
        public int Init()
        {
            MyCamera.MV_GIGE_DEVICE_INFO stGigEDeviceInfo=new MyCamera.MV_GIGE_DEVICE_INFO();
            try
            {
                // ch:枚举设备 | en:Enum device
                MyCamera.MV_CC_DEVICE_INFO_LIST stDevList = new MyCamera.MV_CC_DEVICE_INFO_LIST();
                nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref stDevList);
                if (MyCamera.MV_OK != nRet)
                {
                    _log.Error(string.Format("Enum device failed:{0:x8}", nRet));
                    return -1;
                }
                _log.Imformation("Enum device count : " + Convert.ToString(stDevList.nDeviceNum));
                if (0 == stDevList.nDeviceNum)
                {
                    return -1;
                }
                MyCamera.MV_CC_DEVICE_INFO stDevInfo;  
                // ch:打印设备信息 en:Print device info
                for (Int32 i = 0; i < stDevList.nDeviceNum; i++)
                {
                    stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));
                    if (MyCamera.MV_GIGE_DEVICE == stDevInfo.nTLayerType)
                    {
                        stGigEDeviceInfo = (MyCamera.MV_GIGE_DEVICE_INFO)MyCamera.ByteToStruct(stDevInfo.SpecialInfo.stGigEInfo, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
                        uint nIp1 = ((stGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24);
                        uint nIp2 = ((stGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16);
                        uint nIp3 = ((stGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8);
                        uint nIp4 = (stGigEDeviceInfo.nCurrentIp & 0x000000ff);
                        _log.Imformation("\n" + i.ToString() + ": [GigE] User Define Name : " + stGigEDeviceInfo.chUserDefinedName);
                        _log.Imformation("device IP :" + nIp1 + "." + nIp2 + "." + nIp3 + "." + nIp4);
                    }
                    else if (MyCamera.MV_USB_DEVICE == stDevInfo.nTLayerType)
                    {
                        MyCamera.MV_USB3_DEVICE_INFO stUsb3DeviceInfo = (MyCamera.MV_USB3_DEVICE_INFO)MyCamera.ByteToStruct(stDevInfo.SpecialInfo.stUsb3VInfo, typeof(MyCamera.MV_USB3_DEVICE_INFO));
                        _log.Imformation("\n" + i.ToString() + ": [U3V] User Define Name : " + stUsb3DeviceInfo.chUserDefinedName);
                        _log.Imformation("\n Serial Number : " + stUsb3DeviceInfo.chSerialNumber);
                        _log.Imformation("\n Device Number : " + stUsb3DeviceInfo.nDeviceNumber);
                    }
                    stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));
                    // 打开特定的相机
                    if(!DeviceIDList.Contains(stGigEDeviceInfo.chUserDefinedName))
                    {
                        continue;
                    }
                    MyCamera device = new MyCamera();
                    // ch:创建设备 | en:Create device
                    nRet = device.MV_CC_CreateDevice_NET(ref stDevInfo);
                    if (MyCamera.MV_OK != nRet)
                    {
                        _log.Imformation(string.Format("Create device failed:{0:x8}", nRet));
                        return -1;
                    }
                    // ch:打开设备 | en:Open device
                    nRet = device.MV_CC_OpenDevice_NET();
                    if (MyCamera.MV_OK != nRet)
                    {
                        _log.Imformation(string.Format("Open device failed:{0:x8}", nRet));
                        return -1;
                    }
                    // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
                    if (stDevInfo.nTLayerType == MyCamera.MV_GIGE_DEVICE)
                    {
                        int nPacketSize = device.MV_CC_GetOptimalPacketSize_NET();
                        if (nPacketSize > 0)
                        {
                            nRet = device.MV_CC_SetIntValue_NET("GevSCPSPacketSize", (uint)nPacketSize);
                            if (nRet != MyCamera.MV_OK)
                            {
                                _log.Imformation(string.Format("Warning: Set Packet Size failed {0:x8}", nRet));
                            }
                        }
                        else
                        {
                            _log.Imformation(string.Format("Warning: Get Packet Size failed {0:x8}", nPacketSize));
                        }
                    }
                    // ch:设置触发模式为off || en:set trigger mode as off
                    if (MyCamera.MV_OK != device.MV_CC_SetEnumValue_NET("TriggerMode", 0))
                    {
                        _log.Imformation("Set TriggerMode failed!");
                        return -1;
                    }
                    _log.Imformation("User Device ID: "+ stGigEDeviceInfo.chUserDefinedName);
                    // ch:获取包大小 || en: Get Payload Size
                    MyCamera.MVCC_INTVALUE stParam = new MyCamera.MVCC_INTVALUE();
                    nRet = device.MV_CC_GetIntValue_NET("PayloadSize", ref stParam);
                    if (MyCamera.MV_OK != nRet)
                    {
                        _log.Imformation(string.Format("Get PayloadSize failed:{0:x8}", nRet));
                        return -1;
                    }
                    if (MyCamera.MV_OK != device.MV_CC_SetEnumValue_NET("ExposureAuto", 1))
                    {
                        _log.Imformation("Set ExposureAuto failed!");
                    }
                    if (MyCamera.MV_OK != device.MV_CC_SetEnumValue_NET("GainAuto", 1))
                    {
                        _log.Imformation("Set GainAuto failed!");
                    }
                    //if (MyCamera.MV_OK != device.MV_CC_SetIntValueEx_NET("Width", CurrentCameraInfo.Width))
                    //{
                    //    _log.Imformation("Set Width failed!");
                    //}
                    //if (MyCamera.MV_OK != device.MV_CC_SetIntValueEx_NET("Height", CurrentCameraInfo.Height))
                    //{
                    //    _log.Imformation("Set Height failed!");
                    //}
                    nPayloadSize = stParam.nCurValue;
                    // ch:开启抓图 | en:start grab
                    nRet = device.MV_CC_StartGrabbing_NET();
                    if (MyCamera.MV_OK != nRet)
                    {
                        _log.Imformation(string.Format("Start grabbing failed:{0:x8}", nRet));
                        return -1;
                    }
                    
                    _deviceDict.Add(stGigEDeviceInfo.chUserDefinedName, device);
                }
                Connected = true;
                return 0;
            }
            catch (Exception e)
            {
                _log.Error("Init Error ",e);
                return -1;
            }
        }
        public int GrabImg()
        {
            try
            {
                MyCamera device = _deviceDict[CurrentCameraInfo.DeviceID];
                int nCount = 0;
                MyCamera.MV_FRAME_OUT FrameInfo = new MyCamera.MV_FRAME_OUT();
                while (nCount++ != 1)
                {
                    nRet = device.MV_CC_GetImageBuffer_NET(ref FrameInfo, 1000);
                    // ch:获取一帧图像 | en:Get one image
                    if (MyCamera.MV_OK == nRet)
                    {
                        _log.Imformation("Get One Frame:" + "Width[" + Convert.ToString(FrameInfo.stFrameInfo.nWidth) + "] , Height[" + Convert.ToString(FrameInfo.stFrameInfo.nHeight)
                                        + "] , FrameLen[" + Convert.ToString(FrameInfo.stFrameInfo.nFrameLen) + "]");
                        // ch:将图像数据保存到本地文件 | en:Save image data to local file
                        byte[] data = new byte[FrameInfo.stFrameInfo.nFrameLen];
                        Marshal.Copy(FrameInfo.pBufAddr, data, 0, (int)FrameInfo.stFrameInfo.nFrameLen);
                        ImCtnr = new HImageContainer();
                        ImCtnr.TextWidth = FrameInfo.stFrameInfo.nWidth;
                        ImCtnr.TextHeight = FrameInfo.stFrameInfo.nHeight;
                        ImCtnr.ImGray = data;
                        ImCtnr.IsRGBEnabled = false;
                        device.MV_CC_FreeImageBuffer_NET(ref FrameInfo);
                        continue;
                    }
                    else
                    {
                        _log.Imformation(string.Format("No data:{0:x8}", nRet));
                    }
                }
                return 0;
            }
            catch (Exception e)
            {
                _log.Error("GrabImg Error " + e.ToString(),e);
                return -1;
            }
        }
        public int Exit()
        {
            try
            {
                foreach (var device in _deviceDict)
                {
                    nRet = device.Value.MV_CC_StopGrabbing_NET();
                    if (MyCamera.MV_OK != nRet)
                    {
                        _log.Imformation(string.Format("Stop grabbing failed{0:x8}", nRet));
                        return -1;
                    }
                    // ch:关闭设备 | en:Close device
                    nRet = device.Value.MV_CC_CloseDevice_NET();
                    if (MyCamera.MV_OK != nRet)
                    {
                        _log.Imformation(string.Format("Close device failed{0:x8}", nRet));
                        return -1;
                    }
                    // ch:销毁设备 | en:Destroy device
                    nRet = device.Value.MV_CC_DestroyDevice_NET();
                    if (MyCamera.MV_OK != nRet)
                    {
                        _log.Imformation(string.Format("Destroy device failed:{0:x8}", nRet));
                        return -1;
                    }
                }
                _deviceDict.Clear();
                Connected = false;
                return 0;
            }
            catch (Exception e)
            {
                _log.Error("Exit Error ", e);
                return -1;
            }
        }

        public int StopRecord()
        {
            throw new NotImplementedException();
        }
    }
}
